5.2.4 Exercises
- Find all flights that
- Had an arrival delay of two or more hours
filter(flights, arr_delay >= 2)
b. Flew to Houston (IAH or HOU)
flights_departed <- filter(flights, !(is.na(dep_time))) # extract only the flights which left
filter(flights_departed, dest=="IAH" | dest=="HOU")
c. Were operated by United, American, or Delta
filter(flights_departed, carrier=="UA" | carrier=="AA" | carrier=="DL")
d. Departed in summer (July, August, and September)
filter(flights_departed, month == 7 | month == 8 | month == 9)
filter(flights_departed, month %in% c(7:9))
e. Arrived more than two hours late, but didn’t leave late
filter(flights_departed, arr_delay > 120 & !(dep_delay > 0))
f. Were delayed by at least an hour, but made up over 30 minutes in flight
filter(flights_departed, dep_delay >= 60 & (dep_delay - arr_delay) > 30)
g. Departed between midnight and 6am (inclusive)
filter(flights_departed, !(dep_time > 0600 & dep_time < 2400))
2. Another useful dplyr filtering helper is between(). What does it do? Can you use it to simplify the code needed to answer the previous challenges?
between() is a shortcut for x >= left & x <= right
Departed in summer (July, August, and September)
flights_departed[between(flights$month, 7, 9),]
Departed between midnight and 6am (inclusive)
flights_departed[!(between(flights_departed$dep_time, 601, 2359)),]
3. How many flights have a missing dep_time? What other variables are missing? What might these rows represent?
sum(is.na(flights$dep_time))
[1] 8255
head(filter(flights, (is.na(dep_time))))
Missing dep_time means that the flight didn’t depart. Therefore, the following variables do not exist in the flight.
Dep_time, dep_delay, arr_time, arr_delay and air_time
4. Why is NA ^ 0 not missing? Why is NA | TRUE not missing? Why is FALSE & NA not missing? Can you figure out the general rule? (NA * 0 is a tricky counterexample!)
NA ^ 0 # (anything) ^ 0 always returns 1
[1] 1
NA | TRUE # '|' returns TRUE if either is TRUE and FALSE if both are FALSE.
[1] TRUE
NA | FALSE # returns the missing value because it is not the case above.
[1] NA
FALSE & NA # '&' returns TRUE if both are TRUE and FALSE if either is FALSE.
[1] FALSE
TRUE & NA # returns the missing value becasue it is not the case above .
[1] NA
NA * 0 # '*' requires two real numbers for the calculation
[1] NA
General rule) The calculation result including NA depends on each operator.
5.3.1 Exercises
1. How could you use arrange() to sort all missing values to the start? (Hint: use is.na()).
arrange(flights, is.na(dep_time)) # missing values to the end
arrange(flights, desc(is.na(dep_time))) # missing values to the start
2. Sort flights to find the most delayed flights. Find the flights that left earliest.
arrange(flights_departed, desc(dep_delay))
arrange(flights_departed, dep_delay)
the most delayed flight: HA 51 departed 1301 min later than scheduled
the flight that left earliest: B6 97 departed 43 min earlier than scheduled
3. Sort flights to find the fastest flights.
arrange(flights_departed, desc(distance/air_time))
DL 1499 travelled 762 miles in 65 min.
4. Which flights travelled the longest? Which travelled the shortest?
arrange(flights_departed, desc(distance))
arrange(flights_departed, distance)
The flights from JFK to HNL travelled 4983 miles.
The flights from EWR to LGA travelled 80 miles.
5.4.1 Exercises
1. Brainstorm as many ways as possible to select dep_time, dep_delay, arr_time, and arr_delay from flights.
select(flights, dep_time, dep_delay, arr_time, arr_delay)
select(flights, starts_with("dep"), starts_with("arr"))
2. What happens if you include the name of a variable multiple times in a select() call?
select(flights, dep_time, dep_time)
The variable value is returned only once.
3. What does the one_of() function do? Why might it be helpful in conjunction with this vector?
vars <- c("year", "month", "day", "dep_delay", "arr_delay")
select(flights, one_of(vars))
one_of() selects variables in character vector.
4. Does the result of running the following code surprise you? How do the select helpers deal with case by default? How can you change that default?
select(flights, contains("TIME")) # default: case insensitive
select(flights, contains("TIME", ignore.case = FALSE)) # case sensitive
default: ignore.case = TRUE
5.5.2 Exercises
1. Currently dep_time and sched_dep_time are convenient to look at, but hard to compute with because they’re not really continuous numbers. Convert them to a more convenient representation of number of minutes since midnight.
tempo <- mutate(flights,
dep_minutes = dep_time %/% 100*60 + dep_time %% 100,
sched_dep_minutes = sched_dep_time %/% 100*60 + sched_dep_time %% 100) # convert into number of minutes
select(tempo, dep_time, dep_minutes, sched_dep_time, sched_dep_minutes) # easy to calculate (in number of minutes)
2. Compare air_time with arr_time - dep_time. What do you expect to see? What do you see? What do you need to do to fix it?
a <- transmute(flights, air_time, difference = arr_time - dep_time)
Dep_time and arv_time depend on the timezone of departure and arrival airport. So we need to convert dep_time and arr_time into standardized time by applying local time zone and Daylight Saving Time(DST)
e.g. Davis UTC -7
New York UTC -4
London UTC -1
3. Compare dep_time, sched_dep_time, and dep_delay. How would you expect those three numbers to be related?
transmute(flights, dep_time, sched_dep_time, dep_delay)
dep_delay = dep_time - sched_dep_time
4. Find the 10 most delayed flights using a ranking function. How do you want to handle ties? Carefully read the documentation for min_rank().
arrange(flights, min_rank(desc(dep_delay)))
min_rank(): gives smallest values the small ranks, equivalent to rank(ties.method=“min”)
5. What does 1:3 + 1:10 return? Why?
1:3 + 1:10
longer object length is not a multiple of shorter object length
[1] 2 4 6 5 7 9 8 10 12 11
The elements of the small vector are recycled until all elements of the long vector are manipulated by the operator.
1:3 + 1:9
[1] 2 4 6 5 7 9 8 10 12
6. What trigonometric functions does R provide?
Usage (x, y: numeric or complex vectors)
cos(x) cosine sin(x) sine tan(x) tangent
acos(x) arc-cosine asin(x) arc-sine atan(x) arc-tangent atan2(y, x) two-argument arc-tangent
cospi(x) cos(pix) sinpi(x) sin(pix) tanpi(x) tan(pi*x)
LS0tIAp0aXRsZTogIkNoNS4gRGF0YSBUcmFuc2Zvcm1hdGlvbigxKSIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBodG1sX2RvY3VtZW50OgogICAga2VlcF9tZDogeWVzCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0Ci0tLQpgYGB7ciBpbmNsdWRlPUZBTFNFfQpsaWJyYXJ5KG55Y2ZsaWdodHMxMykKbGlicmFyeSh0aWR5dmVyc2UpCmBgYApcCiAgCiAgCiMjIyMgNS4yLjQgRXhlcmNpc2VzICAKClwgCgoxLiBGaW5kIGFsbCBmbGlnaHRzIHRoYXQKXAphLiBIYWQgYW4gYXJyaXZhbCBkZWxheSBvZiB0d28gb3IgbW9yZSBob3VycwpgYGB7cn0KZmlsdGVyKGZsaWdodHMsIGFycl9kZWxheSA+PSAyKQpgYGAKXApiLiBGbGV3IHRvIEhvdXN0b24gKElBSCBvciBIT1UpCmBgYHtyfQpmbGlnaHRzX2RlcGFydGVkIDwtIGZpbHRlcihmbGlnaHRzLCAhKGlzLm5hKGRlcF90aW1lKSkpICMgZXh0cmFjdCBvbmx5IHRoZSBmbGlnaHRzIHdoaWNoIGxlZnQKZmlsdGVyKGZsaWdodHNfZGVwYXJ0ZWQsIGRlc3Q9PSJJQUgiIHwgZGVzdD09IkhPVSIpCmBgYApcCmMuIFdlcmUgb3BlcmF0ZWQgYnkgVW5pdGVkLCBBbWVyaWNhbiwgb3IgRGVsdGEKYGBge3J9CmZpbHRlcihmbGlnaHRzX2RlcGFydGVkLCBjYXJyaWVyPT0iVUEiIHwgY2Fycmllcj09IkFBIiB8IGNhcnJpZXI9PSJETCIpCmBgYApcCmQuIERlcGFydGVkIGluIHN1bW1lciAoSnVseSwgQXVndXN0LCBhbmQgU2VwdGVtYmVyKQpgYGB7cn0KZmlsdGVyKGZsaWdodHNfZGVwYXJ0ZWQsIG1vbnRoID09IDcgfCBtb250aCA9PSA4IHwgbW9udGggPT0gOSkKZmlsdGVyKGZsaWdodHNfZGVwYXJ0ZWQsIG1vbnRoICVpbiUgYyg3OjkpKQpgYGAKXAplLiBBcnJpdmVkIG1vcmUgdGhhbiB0d28gaG91cnMgbGF0ZSwgYnV0IGRpZG7igJl0IGxlYXZlIGxhdGUKYGBge3J9CmZpbHRlcihmbGlnaHRzX2RlcGFydGVkLCBhcnJfZGVsYXkgPiAxMjAgJiAhKGRlcF9kZWxheSA+IDApKQpgYGAKXApmLiBXZXJlIGRlbGF5ZWQgYnkgYXQgbGVhc3QgYW4gaG91ciwgYnV0IG1hZGUgdXAgb3ZlciAzMCBtaW51dGVzIGluIGZsaWdodApgYGB7cn0KZmlsdGVyKGZsaWdodHNfZGVwYXJ0ZWQsIGRlcF9kZWxheSA+PSA2MCAmIChkZXBfZGVsYXkgLSBhcnJfZGVsYXkpID4gMzApCmBgYApcCmcuIERlcGFydGVkIGJldHdlZW4gbWlkbmlnaHQgYW5kIDZhbSAoaW5jbHVzaXZlKQpgYGB7cn0KZmlsdGVyKGZsaWdodHNfZGVwYXJ0ZWQsICEoZGVwX3RpbWUgPiAwNjAwICYgZGVwX3RpbWUgPCAyNDAwKSkKYGBgClwKMi4gQW5vdGhlciB1c2VmdWwgZHBseXIgZmlsdGVyaW5nIGhlbHBlciBpcyBiZXR3ZWVuKCkuIFdoYXQgZG9lcyBpdCBkbz8gQ2FuIHlvdSB1c2UgaXQgdG8gc2ltcGxpZnkgdGhlIGNvZGUgbmVlZGVkIHRvIGFuc3dlciB0aGUgcHJldmlvdXMgY2hhbGxlbmdlcz8KClwKYmV0d2VlbigpIGlzIGEgc2hvcnRjdXQgZm9yIHggPj0gbGVmdCAmIHggPD0gcmlnaHQKClwKRGVwYXJ0ZWQgaW4gc3VtbWVyIChKdWx5LCBBdWd1c3QsIGFuZCBTZXB0ZW1iZXIpCmBgYHtyfQpmbGlnaHRzX2RlcGFydGVkW2JldHdlZW4oZmxpZ2h0cyRtb250aCwgNywgOSksXQpgYGAKXApEZXBhcnRlZCBiZXR3ZWVuIG1pZG5pZ2h0IGFuZCA2YW0gKGluY2x1c2l2ZSkKYGBge3J9CmZsaWdodHNfZGVwYXJ0ZWRbIShiZXR3ZWVuKGZsaWdodHNfZGVwYXJ0ZWQkZGVwX3RpbWUsIDYwMSwgMjM1OSkpLF0KYGBgClwKMy4gSG93IG1hbnkgZmxpZ2h0cyBoYXZlIGEgbWlzc2luZyBkZXBfdGltZT8gV2hhdCBvdGhlciB2YXJpYWJsZXMgYXJlIG1pc3Npbmc/IFdoYXQgbWlnaHQgdGhlc2Ugcm93cyByZXByZXNlbnQ/CmBgYHtyfQpzdW0oaXMubmEoZmxpZ2h0cyRkZXBfdGltZSkpCmhlYWQoZmlsdGVyKGZsaWdodHMsIChpcy5uYShkZXBfdGltZSkpKSkKYGBgCk1pc3NpbmcgZGVwX3RpbWUgbWVhbnMgdGhhdCB0aGUgZmxpZ2h0IGRpZG4ndCBkZXBhcnQuIFRoZXJlZm9yZSwgdGhlIGZvbGxvd2luZyB2YXJpYWJsZXMgZG8gbm90IGV4aXN0IGluIHRoZSBmbGlnaHQuXApEZXBfdGltZSwgZGVwX2RlbGF5LCBhcnJfdGltZSwgYXJyX2RlbGF5IGFuZCBhaXJfdGltZQoKXAo0LiBXaHkgaXMgTkEgXiAwIG5vdCBtaXNzaW5nPyBXaHkgaXMgTkEgfCBUUlVFIG5vdCBtaXNzaW5nPyBXaHkgaXMgRkFMU0UgJiBOQSBub3QgbWlzc2luZz8gQ2FuIHlvdSBmaWd1cmUgb3V0IHRoZSBnZW5lcmFsIHJ1bGU/IChOQSAqIDAgaXMgYSB0cmlja3kgY291bnRlcmV4YW1wbGUhKQoKYGBge3J9Ck5BIF4gMCAjIChhbnl0aGluZykgXiAwIGFsd2F5cyByZXR1cm5zIDEKYGBgCgpgYGB7cn0KTkEgfCBUUlVFICAjICd8JyByZXR1cm5zIFRSVUUgaWYgZWl0aGVyIGlzIFRSVUUgYW5kIEZBTFNFIGlmIGJvdGggYXJlIEZBTFNFLgpOQSB8IEZBTFNFICMgcmV0dXJucyB0aGUgbWlzc2luZyB2YWx1ZSBiZWNhdXNlIGl0IGlzIG5vdCB0aGUgY2FzZSBhYm92ZS4KYGBgCgpgYGB7cn0KRkFMU0UgJiBOQSAjICcmJyByZXR1cm5zIFRSVUUgaWYgYm90aCBhcmUgVFJVRSBhbmQgRkFMU0UgaWYgZWl0aGVyIGlzIEZBTFNFLgpUUlVFICYgTkEgIyByZXR1cm5zIHRoZSBtaXNzaW5nIHZhbHVlIGJlY2FzdWUgaXQgaXMgbm90IHRoZSBjYXNlIGFib3ZlIC4KYGBgCmBgYHtyfQpOQSAqIDAgIyAnKicgcmVxdWlyZXMgdHdvIHJlYWwgbnVtYmVycyBmb3IgdGhlIGNhbGN1bGF0aW9uCmBgYApHZW5lcmFsIHJ1bGUpIFRoZSBjYWxjdWxhdGlvbiByZXN1bHQgaW5jbHVkaW5nIE5BIGRlcGVuZHMgb24gZWFjaCBvcGVyYXRvci4KClwKCgojIyMjIDUuMy4xIEV4ZXJjaXNlcwoKXAoxLiBIb3cgY291bGQgeW91IHVzZSBhcnJhbmdlKCkgdG8gc29ydCBhbGwgbWlzc2luZyB2YWx1ZXMgdG8gdGhlIHN0YXJ0PyAoSGludDogdXNlIGlzLm5hKCkpLgpgYGB7cn0KYXJyYW5nZShmbGlnaHRzLCBpcy5uYShkZXBfdGltZSkpICMgbWlzc2luZyB2YWx1ZXMgdG8gdGhlIGVuZAphcnJhbmdlKGZsaWdodHMsIGRlc2MoaXMubmEoZGVwX3RpbWUpKSkgIyBtaXNzaW5nIHZhbHVlcyB0byB0aGUgc3RhcnQKYGBgClwKMi4gU29ydCBmbGlnaHRzIHRvIGZpbmQgdGhlIG1vc3QgZGVsYXllZCBmbGlnaHRzLiBGaW5kIHRoZSBmbGlnaHRzIHRoYXQgbGVmdCBlYXJsaWVzdC4KYGBge3J9CmFycmFuZ2UoZmxpZ2h0c19kZXBhcnRlZCwgZGVzYyhkZXBfZGVsYXkpKQphcnJhbmdlKGZsaWdodHNfZGVwYXJ0ZWQsIGRlcF9kZWxheSkKYGBgCnRoZSBtb3N0IGRlbGF5ZWQgZmxpZ2h0OiBIQSA1MSBkZXBhcnRlZCAxMzAxIG1pbiBsYXRlciB0aGFuIHNjaGVkdWxlZFwKdGhlIGZsaWdodCB0aGF0IGxlZnQgZWFybGllc3Q6IEI2IDk3IGRlcGFydGVkIDQzIG1pbiBlYXJsaWVyIHRoYW4gc2NoZWR1bGVkCgpcCjMuIFNvcnQgZmxpZ2h0cyB0byBmaW5kIHRoZSBmYXN0ZXN0IGZsaWdodHMuCmBgYHtyfQphcnJhbmdlKGZsaWdodHNfZGVwYXJ0ZWQsIGRlc2MoZGlzdGFuY2UvYWlyX3RpbWUpKQpgYGAKREwgMTQ5OSB0cmF2ZWxsZWQgNzYyIG1pbGVzIGluIDY1IG1pbi4KClwKNC4gV2hpY2ggZmxpZ2h0cyB0cmF2ZWxsZWQgdGhlIGxvbmdlc3Q/IFdoaWNoIHRyYXZlbGxlZCB0aGUgc2hvcnRlc3Q/CmBgYHtyfQphcnJhbmdlKGZsaWdodHNfZGVwYXJ0ZWQsIGRlc2MoZGlzdGFuY2UpKQphcnJhbmdlKGZsaWdodHNfZGVwYXJ0ZWQsIGRpc3RhbmNlKQpgYGAKVGhlIGZsaWdodHMgZnJvbSBKRksgdG8gSE5MIHRyYXZlbGxlZCA0OTgzIG1pbGVzLlwKVGhlIGZsaWdodHMgZnJvbSBFV1IgdG8gTEdBIHRyYXZlbGxlZCA4MCBtaWxlcy4KClwKCgojIyMjIDUuNC4xIEV4ZXJjaXNlcwpcCjEuIEJyYWluc3Rvcm0gYXMgbWFueSB3YXlzIGFzIHBvc3NpYmxlIHRvIHNlbGVjdCBkZXBfdGltZSwgZGVwX2RlbGF5LCBhcnJfdGltZSwgYW5kIGFycl9kZWxheSBmcm9tIGZsaWdodHMuCmBgYHtyfQpzZWxlY3QoZmxpZ2h0cywgZGVwX3RpbWUsIGRlcF9kZWxheSwgYXJyX3RpbWUsIGFycl9kZWxheSkKc2VsZWN0KGZsaWdodHMsIHN0YXJ0c193aXRoKCJkZXAiKSwgc3RhcnRzX3dpdGgoImFyciIpKQpgYGAKXAoyLiBXaGF0IGhhcHBlbnMgaWYgeW91IGluY2x1ZGUgdGhlIG5hbWUgb2YgYSB2YXJpYWJsZSBtdWx0aXBsZSB0aW1lcyBpbiBhIHNlbGVjdCgpIGNhbGw/CmBgYHtyfQpzZWxlY3QoZmxpZ2h0cywgZGVwX3RpbWUsIGRlcF90aW1lKQpgYGAKVGhlIHZhcmlhYmxlIHZhbHVlIGlzIHJldHVybmVkIG9ubHkgb25jZS4KXAozLiBXaGF0IGRvZXMgdGhlIG9uZV9vZigpIGZ1bmN0aW9uIGRvPyBXaHkgbWlnaHQgaXQgYmUgaGVscGZ1bCBpbiBjb25qdW5jdGlvbiB3aXRoIHRoaXMgdmVjdG9yPwpgYGB7cn0KdmFycyA8LSBjKCJ5ZWFyIiwgIm1vbnRoIiwgImRheSIsICJkZXBfZGVsYXkiLCAiYXJyX2RlbGF5IikKc2VsZWN0KGZsaWdodHMsIG9uZV9vZih2YXJzKSkKYGBgCm9uZV9vZigpIHNlbGVjdHMgdmFyaWFibGVzIGluIGNoYXJhY3RlciB2ZWN0b3IuCgpcCjQuIERvZXMgdGhlIHJlc3VsdCBvZiBydW5uaW5nIHRoZSBmb2xsb3dpbmcgY29kZSBzdXJwcmlzZSB5b3U/IEhvdyBkbyB0aGUgc2VsZWN0IGhlbHBlcnMgZGVhbCB3aXRoIGNhc2UgYnkgZGVmYXVsdD8gSG93IGNhbiB5b3UgY2hhbmdlIHRoYXQgZGVmYXVsdD8KYGBge3J9CnNlbGVjdChmbGlnaHRzLCBjb250YWlucygiVElNRSIpKSAjIGRlZmF1bHQ6IGNhc2UgaW5zZW5zaXRpdmUKc2VsZWN0KGZsaWdodHMsIGNvbnRhaW5zKCJUSU1FIiwgaWdub3JlLmNhc2UgPSBGQUxTRSkpICMgY2FzZSBzZW5zaXRpdmUKYGBgCmRlZmF1bHQ6IGlnbm9yZS5jYXNlID0gVFJVRQoKXAoKCiMjIyMgNS41LjIgRXhlcmNpc2VzClwKMS4gQ3VycmVudGx5IGRlcF90aW1lIGFuZCBzY2hlZF9kZXBfdGltZSBhcmUgY29udmVuaWVudCB0byBsb29rIGF0LCBidXQgaGFyZCB0byBjb21wdXRlIHdpdGggYmVjYXVzZSB0aGV54oCZcmUgbm90IHJlYWxseSBjb250aW51b3VzIG51bWJlcnMuIENvbnZlcnQgdGhlbSB0byBhIG1vcmUgY29udmVuaWVudCByZXByZXNlbnRhdGlvbiBvZiBudW1iZXIgb2YgbWludXRlcyBzaW5jZSBtaWRuaWdodC4KCmBgYHtyfQp0ZW1wbyA8LSBtdXRhdGUoZmxpZ2h0cywKICBkZXBfbWludXRlcyA9IGRlcF90aW1lICUvJSAxMDAqNjAgKyBkZXBfdGltZSAlJSAxMDAsIAogIHNjaGVkX2RlcF9taW51dGVzID0gc2NoZWRfZGVwX3RpbWUgJS8lIDEwMCo2MCArIHNjaGVkX2RlcF90aW1lICUlIDEwMCkgIyBjb252ZXJ0IGludG8gbnVtYmVyIG9mIG1pbnV0ZXMgIApzZWxlY3QodGVtcG8sIGRlcF90aW1lLCBkZXBfbWludXRlcywgc2NoZWRfZGVwX3RpbWUsIHNjaGVkX2RlcF9taW51dGVzKSAjIGVhc3kgdG8gY2FsY3VsYXRlIChpbiBudW1iZXIgb2YgbWludXRlcykKYGBgCgpcCjIuIENvbXBhcmUgYWlyX3RpbWUgd2l0aCBhcnJfdGltZSAtIGRlcF90aW1lLiBXaGF0IGRvIHlvdSBleHBlY3QgdG8gc2VlPyBXaGF0IGRvIHlvdSBzZWU/IFdoYXQgZG8geW91IG5lZWQgdG8gZG8gdG8gZml4IGl0PwoKYGBge3J9CmEgPC0gdHJhbnNtdXRlKGZsaWdodHMsIGFpcl90aW1lLCBkaWZmZXJlbmNlID0gYXJyX3RpbWUgLSBkZXBfdGltZSkKCmBgYApEZXBfdGltZSBhbmQgYXJ2X3RpbWUgZGVwZW5kIG9uIHRoZSB0aW1lem9uZSBvZiBkZXBhcnR1cmUgYW5kIGFycml2YWwgYWlycG9ydC4gU28gd2UgbmVlZCB0byBjb252ZXJ0IGRlcF90aW1lIGFuZCBhcnJfdGltZSBpbnRvIHN0YW5kYXJkaXplZCB0aW1lIGJ5IGFwcGx5aW5nIGxvY2FsIHRpbWUgem9uZSBhbmQgRGF5bGlnaHQgU2F2aW5nIFRpbWUoRFNUKVwKZS5nLiBEYXZpcyBVVEMgLTdcCiAgICAgTmV3IFlvcmsgVVRDIC00XAogICAgIExvbmRvbiBVVEMgLTEKICAgICAKXAozLiBDb21wYXJlIGRlcF90aW1lLCBzY2hlZF9kZXBfdGltZSwgYW5kIGRlcF9kZWxheS4gSG93IHdvdWxkIHlvdSBleHBlY3QgdGhvc2UgdGhyZWUgbnVtYmVycyB0byBiZSByZWxhdGVkPwpgYGB7cn0KdHJhbnNtdXRlKGZsaWdodHMsIGRlcF90aW1lLCBzY2hlZF9kZXBfdGltZSwgZGVwX2RlbGF5KQpgYGAKZGVwX2RlbGF5ID0gZGVwX3RpbWUgLSBzY2hlZF9kZXBfdGltZQoKXAo0LiBGaW5kIHRoZSAxMCBtb3N0IGRlbGF5ZWQgZmxpZ2h0cyB1c2luZyBhIHJhbmtpbmcgZnVuY3Rpb24uIEhvdyBkbyB5b3Ugd2FudCB0byBoYW5kbGUgdGllcz8gQ2FyZWZ1bGx5IHJlYWQgdGhlIGRvY3VtZW50YXRpb24gZm9yIG1pbl9yYW5rKCkuCmBgYHtyfQphcnJhbmdlKGZsaWdodHMsIG1pbl9yYW5rKGRlc2MoZGVwX2RlbGF5KSkpCmBgYAptaW5fcmFuaygpOiBnaXZlcyBzbWFsbGVzdCB2YWx1ZXMgdGhlIHNtYWxsIHJhbmtzLCBlcXVpdmFsZW50IHRvIHJhbmsodGllcy5tZXRob2Q9Im1pbiIpIAoKXAo1LiBXaGF0IGRvZXMgMTozICsgMToxMCByZXR1cm4/IFdoeT8KYGBge3J9CjE6MyArIDE6MTAKYGBgClRoZSBlbGVtZW50cyBvZiB0aGUgc21hbGwgdmVjdG9yIGFyZSByZWN5Y2xlZCB1bnRpbCBhbGwgZWxlbWVudHMgb2YgdGhlIGxvbmcgdmVjdG9yIGFyZSBtYW5pcHVsYXRlZCBieSB0aGUgb3BlcmF0b3IuCgpgYGB7cn0KMTozICsgMTo5CmBgYAoKXAo2LiBXaGF0IHRyaWdvbm9tZXRyaWMgZnVuY3Rpb25zIGRvZXMgUiBwcm92aWRlPwoKVXNhZ2UgKHgsIHk6IG51bWVyaWMgb3IgY29tcGxleCB2ZWN0b3JzKQoKY29zKHgpIGNvc2luZQpzaW4oeCkgc2luZQp0YW4oeCkgdGFuZ2VudAoKYWNvcyh4KSBhcmMtY29zaW5lCmFzaW4oeCkgYXJjLXNpbmUKYXRhbih4KSBhcmMtdGFuZ2VudAphdGFuMih5LCB4KSB0d28tYXJndW1lbnQgYXJjLXRhbmdlbnQKCmNvc3BpKHgpIGNvcyhwaSp4KQpzaW5waSh4KSBzaW4ocGkqeCkKdGFucGkoeCkgdGFuKHBpKngpCgoKCgoKCgoKCgoKCg==